#pragma once
#ifndef __LIT_STRING_HH__
#define __LIT_STRING_HH__

#include <LitExport.hpp>
#include <LitForward.hpp>
	
#include <string>
#include <sstream>
#include <ostream>

#ifdef LIT_OGRE_SUPPORT
	#include <OgreString.h>
#endif

namespace Lit
{
	class LIT_API String;
	class LIT_API StringPrivates;
	class LIT_API StringVector;
	class LIT_API StringVectorPrivates;
	
	class LIT_API StringIterPrivates;
	class LIT_API StringConstIterPrivates;
	class LIT_API StringIter
	{
	public:
		StringIter( );
		StringIter( const String& str, const size_t offset_ = 0 );
		StringIter( const StringIter& rk );
		~StringIter();

		StringIter& operator=( const StringIter& rk );

		bool operator==( const StringIter & rk ) const;
		bool operator!=( const StringIter& rk ) const;

	private:
		void _alloc();
		void _alloc( const StringIter& rk );
		void _alloc( const size_t pos, const String& str );
		void _dealloc();

		StringIterPrivates * mPrivates;
	};
	class LIT_API StringConstIter
	{
	public:
		StringConstIter( );
		StringConstIter( const String& str, const size_t offset_ = 0 );
		StringConstIter( const StringConstIter& rk );
		~StringConstIter();
		
		bool operator==( const StringConstIter & rk ) const;
		bool operator!=( const StringConstIter& rk ) const;

		StringConstIter& operator=( const StringConstIter& rk );

	private:
		void _alloc();
		void _alloc( const StringConstIter& rk );
		void _alloc( const size_t pos, const String& str );
		void _dealloc();

		StringConstIterPrivates * mPrivates;
	};

	class LIT_API String
	{
		friend class LIT_API StringPrivates;
		friend class LIT_API StringVector;
		friend class LIT_API StringVectorPrivates;
		friend class LIT_API StringIterPrivates;
		friend class LIT_API StringConstIterPrivates;
	public:
		typedef StringIter		iterator;
		typedef StringConstIter const_iterator;

#ifdef LIT_UNICODE
		typedef wchar_t char_type;
#else
		typedef char char_type;
#endif
		static const char_type WhiteSpace;
		static const size_t npos;
		
		String( );
#ifdef LIT_OGRE_SUPPORT
		String( const Ogre::String & str );
#endif
		String( const char_type elem );
		String( const size_t count, const char_type fill = ' ' );
		String( const char_type* str );
		String( const String& rk );
		~String( );
		

		template<typename T>  static String from( const T & any )
		{
#			ifdef LIT_UNICODE
			std::wstringstream ss;
#			else
			std::stringstream ss;
#			endif
			ss << any;

			return String( ss.str().c_str() );
		}
		template<typename T> T to() const
		{
#			ifdef LIT_UNICODE
			std::wstringstream ss(mPrivates->mData);
#			else
			std::stringstream ss(mPrivates->mData);

			T ret = T();
			ss >> ret;
			return ret;
#			endif
		}

		iterator begin();
		iterator end();
		const_iterator begin() const;
		const_iterator end() const;

#ifdef LIT_OGRE_SUPPORT
		operator Ogre::String() const;
#endif
		String& operator=( const String& rk );
		
		bool operator==( const String &rk ) const;
		bool operator!=( const String &rk ) const;

		bool operator==( const char_type *rk ) const;
		bool operator!=( const char_type* rk ) const;
		String& operator=( const char_type* rk );	
		const char_type* data() const;
		
		StringVector split( const String &delim = String(WhiteSpace) ) const;
		String substr( const size_t offset, const size_t count = npos ) const;

		char_type& at( const size_t id );
		const char_type& at( const size_t id ) const;

		size_t find( const String &str ) const;
		size_t rfind( const String &str ) const;

		void erase( const size_t offset, const size_t count = 1 );
		size_t size() const;
		bool empty() const;
		void clear() const;

		size_t hash() const;
		
		size_t resize( size_t sz );
		size_t resize( size_t sz, char_type ch );
		size_t reserve( size_t capacit );
		size_t capacity() const;
		
		String trimmed( char_type trimmed_char = ' ' ) const;
		String& trim(char_type trimmed_char = ' ');
		
		bool matches( const String &rk, bool case_sensitive = false ) const;
		String toLower() const;
		String toUpper() const;
		
		String replaceAll( const String &what, const String &by_what, bool case_sensitive ) const;
		String& replaceAll( const String &what, const String &by_what, bool case_sensitive );

		char_type& operator[]( const size_t id );
		
		String& operator+=( const String &rk );
		String operator+( const String &rk ) const;
		
		String& operator+=( const char_type* rk );
		String operator+( const char_type* rk ) const;

		String& operator+=( const char_type rk );
		String operator+( const char_type rk ) const;
		
		String& operator()( const String &rk );		
		String& operator()( const char_type* rk );
		String& operator()( const char_type rk );
		String& operator<<( const String &rk );		
		String& operator<<( const char_type* rk );
		String& operator<<( const char_type rk );
	private:
		StringPrivates* _alloc();

		StringPrivates* _alloc( const char_type* str );
		StringPrivates* _alloc( const size_t count, const char_type fill = ' ' );
		StringPrivates* _copy( const StringPrivates & rk );
		StringPrivates* _desalloc();

		StringPrivates*	mPrivates;
	};

	class LIT_API StringVector
	{
	public:
		static const size_t npos;

		StringVector( );
		StringVector( const StringVector& e );
		~StringVector( );
		StringVector& operator=( const StringVector& vec );
		StringVector& push_back( const String & rk );

		StringVector& operator << ( const String & rk );

		size_t size() const;
		void clear();
		bool empty() const;
		
		void erase( const size_t offset, const size_t count = 1 );

		String& at( const size_t id );
		const String& at( const size_t id ) const;
		
		bool has( const String &str ) const;

		/** Finds a string
			\return The absolute position or StringVector::npos
		*/
		size_t find( const String &str ) const;

		/** Reverse finds a string
			\return The absolute position or StringVector::npos
		*/
		size_t rfind( const String &str ) const;
	private:
		friend class StringVectorPrivates;
		StringVectorPrivates * mPrivates;
	};
};

#ifdef UNICODE
	LIT_API std::wostream&  operator<<( std::wostream& strm, const Lit::String &str );
#else
	LIT_API std::ostream&  operator<<( std::ostream& strm, const Lit::String &str );
#endif
	
LIT_API Lit::String operator+( const Lit::String::char_type* str, const Lit::String& str2 );

template<>
struct LIT_API std::hash<Lit::String>
{
	size_t operator()( const Lit::String & str )
	{
		return str.hash();
	}
};

#endif